Popular Searches
Popular Course Categories
Popular Courses

Understanding application state

Understanding application state

Flutter State Management

Understanding Application State in Flutter

Application state refers to the data that an application needs to keep track of while the application is running and that may need to be shared across multiple widgets, screens, or features.

In Flutter, a useful way to think about state is as the data required to rebuild the UI correctly at any moment. Application state is generally different from temporary widget-specific state because it may need to be accessed by multiple parts of the application or maintained as the user moves through the app.


1. What is Application State?

Application state is information that represents the current condition of an application and can affect what the user sees or what the application does.

For example, an e-commerce application may need to remember:

  • Whether the user is logged in.
  • Which products are in the shopping cart.
  • The selected delivery address.
  • User preferences.
  • Whether notifications have been read.
  • Product data loaded from an API.
  • Current application settings.

Flutter describes application state as information such as user preferences, login information, notifications, shopping-cart contents, and read/unread article status. :contentReference[oaicite:0]{index=0}


2. Simple Definition

You can remember application state with this simple definition:

Application State
=
Data that represents the current condition of the application

Another useful concept is:

UI = f(Application State)

This means that the UI is constructed according to the current state of the application. Flutter follows a declarative UI model in which changing state causes the UI to be rebuilt to represent that state. :contentReference[oaicite:1]{index=1}


3. Examples of Application State

Application State Example
Authentication State User is logged in or logged out
User Profile Name, email, profile information
Shopping Cart Products selected by the user
Theme Light mode or dark mode
Notifications Read and unread notifications
API Data Products, users, articles, orders
Application Settings Language, preferences, configuration
Network State Online, offline, loading, error

4. Application State vs Widget State

One of the most important concepts is understanding the difference between application state and ephemeral state.

Application State Ephemeral State
Usually shared across multiple parts of an application. Usually contained within one widget.
May need to survive navigation or application sessions. Usually temporary.
Examples include login information and shopping cart data. Examples include selected tab or animation progress.
May require a dedicated state-management approach. Often managed with StatefulWidget and setState().

Flutter describes ephemeral state as state that can be neatly contained inside a single widget, while application state is shared more broadly and may need to be retained beyond the lifecycle of an individual widget. :contentReference[oaicite:2]{index=2}


5. Example of Ephemeral State

Suppose a screen has a bottom navigation bar. The currently selected tab might only matter to that screen.

import 'package:flutter/material.dart';

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State createState() => _HomePageState();
}

class _HomePageState extends State {
  int selectedIndex = 0;

  @override
  Widget build(BuildContext context) {
    return BottomNavigationBar(
      currentIndex: selectedIndex,
      onTap: (index) {
        setState(() {
          selectedIndex = index;
        });
      },
      items: const [
        BottomNavigationBarItem(
          icon: Icon(Icons.home),
          label: 'Home',
        ),
        BottomNavigationBarItem(
          icon: Icon(Icons.person),
          label: 'Profile',
        ),
      ],
    );
  }
}

Here, selectedIndex is local to the widget, so using setState() is a natural solution. Flutter's documentation uses the selected tab of a bottom navigation bar as a typical example of ephemeral state. :contentReference[oaicite:3]{index=3}


6. Example of Application State

Consider a shopping application. The cart can be accessed by:

  • Product screen
  • Cart screen
  • Checkout screen
  • Order summary screen

Because multiple parts of the application need the cart, the cart becomes a good example of shared application state.

Product Screen
      |
      ↓
  Cart State
   /      \
  ↓        ↓
Cart     Checkout
Screen    Screen

7. Why is Application State Important?

Application state is important because modern applications contain information that needs to be shared and updated across multiple screens.

For example, after a user logs in:

Login Screen
     ↓
Authentication
     ↓
Logged-in User
     ↓
Home Screen
     ↓
Profile Screen
     ↓
Orders Screen

All of these screens may need information about the currently authenticated user.


8. Application State and Declarative UI

Flutter uses a declarative programming model. Instead of directly telling a widget to change itself, you update the state and allow Flutter to rebuild the UI based on the new state. :contentReference[oaicite:4]{index=4}

For example:

bool isLoggedIn = false;

The UI can be described as:

if (isLoggedIn) {
  return const HomeScreen();
} else {
  return const LoginScreen();
}

When the state changes:

isLoggedIn = true;

The UI should represent the new state:

Login Screen
     ↓
Authentication Successful
     ↓
isLoggedIn = true
     ↓
Home Screen

9. Common Types of Application State

9.1 Authentication State

Authentication state represents whether a user is currently authenticated.

bool isLoggedIn = false;

Possible states include:

  • Not authenticated
  • Authenticating
  • Authenticated
  • Authentication failed

9.2 User State

User state contains information about the current user.

class UserState {
  final String id;
  final String name;
  final String email;

  UserState({
    required this.id,
    required this.name,
    required this.email,
  });
}

9.3 Shopping Cart State

class CartState {
  final List products;

  CartState({
    required this.products,
  });
}

9.4 Theme State

bool isDarkMode = false;

9.5 Network State

enum NetworkStatus {
  idle,
  loading,
  success,
  error,
}

9.6 API Data State

API state can contain:

  • Loading information
  • Retrieved data
  • Error information
  • Empty-data information

10. Application State Lifecycle

Application state commonly follows a cycle:

Initial State
     ↓
User Action / System Event
     ↓
State Changes
     ↓
Notify UI
     ↓
UI Rebuilds
     ↓
New State Displayed

For example:

Cart is Empty
     ↓
User Adds Product
     ↓
Cart State Changes
     ↓
UI Receives New State
     ↓
Cart Badge Shows "1"
     ↓
Cart Screen Shows Product

11. Source of Truth

A good application should have a clear source of truth for important application data.

A source of truth means the place responsible for maintaining the authoritative version of a particular piece of state.

For example:

Cart State
     ↓
Single Source of Truth
     ↓
Product Screen
Cart Screen
Checkout Screen

Having multiple independent copies of the same important data can lead to synchronization problems.


12. Sharing Application State

When several widgets need the same state, the state can be moved higher in the widget tree or exposed through a suitable state-management mechanism.

Flutter's documentation describes this idea as lifting state up: state is kept above the widgets that need to use it. :contentReference[oaicite:5]{index=5}

Parent
  |
  +---- Child A
  |
  +---- Child B
  |
  +---- Child C
Shared State
     ↑
Managed by Parent

13. Lifting State Up

Suppose two widgets need access to the same cart.

Instead of maintaining two different cart objects, keep the cart state in a common ancestor or shared state layer.

MyApp
  |
  ├── ProductList
  |
  └── Cart

The shared cart state can live above both widgets.

This avoids trying to imperatively modify a widget from another unrelated widget. Flutter's declarative model instead encourages constructing widgets from the current state. :contentReference[oaicite:6]{index=6}


14. Application State with ChangeNotifier

ChangeNotifier is a Flutter SDK class that can notify listeners when application data changes.

class CartModel extends ChangeNotifier {
  final List _items = [];

  List get items => List.unmodifiable(_items);

  void addItem(String item) {
    _items.add(item);
    notifyListeners();
  }

  void removeItem(String item) {
    _items.remove(item);
    notifyListeners();
  }

  int get itemCount => _items.length;
}

Calling notifyListeners() signals listening widgets that the state changed and they should update. :contentReference[oaicite:7]{index=7}


15. Application State with Provider

Provider is a community package that can be used to expose and consume shared application state. Flutter's documentation demonstrates Provider together with ChangeNotifier, ChangeNotifierProvider, and Consumer. :contentReference[oaicite:8]{index=8}

Install Provider:

flutter pub add provider

Example state model:

class CartModel extends ChangeNotifier {
  final List _items = [];

  List get items => List.unmodifiable(_items);

  void addItem(String item) {
    _items.add(item);
    notifyListeners();
  }

  void removeItem(String item) {
    _items.remove(item);
    notifyListeners();
  }
}

16. Providing Application State

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (_) => CartModel(),
      child: const MyApp(),
    ),
  );
}

The provider makes the state object available to widgets below it in the widget tree.


17. Reading Application State

final cart = context.watch();

Text(
  'Items: ${cart.items.length}',
)

A widget can also access the model to trigger an action:

context.read().addItem(
  'Flutter Course',
);

The exact API usage depends on the Provider package version and application architecture.


18. Application State and Firebase

Application state becomes especially important when working with Firebase.

For example, a Flutter application using Firebase Authentication can maintain:

Authentication State
       |
       ├── Logged Out
       |
       ├── Loading
       |
       └── Logged In

Cloud Firestore can provide another source of application data:

Firestore
    ↓
Repository / Service
    ↓
Application State
    ↓
Flutter UI

This architecture allows the UI to react to changes in authentication and cloud data.


19. Authentication State Example

StreamBuilder(
  stream: FirebaseAuth.instance.authStateChanges(),
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.waiting) {
      return const Center(
        child: CircularProgressIndicator(),
      );
    }

    if (snapshot.hasData) {
      return const HomeScreen();
    }

    return const LoginScreen();
  },
)

The current authentication state determines which screen is displayed.


20. Application State with API Data

Suppose an application loads a product list from an API.

The application state might look like:

class ProductState {
  final bool isLoading;
  final List products;
  final String? error;

  ProductState({
    required this.isLoading,
    required this.products,
    this.error,
  });
}

Possible state transitions:

Initial
  ↓
Loading
  ↓
Success
  ↓
Products Displayed

Or:

Initial
  ↓
Loading
  ↓
Error
  ↓
Retry

21. Loading State

When data is being retrieved, the application can maintain a loading state.

bool isLoading = true;

The UI can display:

if (isLoading) {
  return const CircularProgressIndicator();
}

22. Success State

After the operation succeeds:

isLoading = false;
products = fetchedProducts;
error = null;

The UI can then display the data.


23. Error State

If the operation fails:

isLoading = false;
error = 'Unable to load products';

The UI can show an error message:

if (error != null) {
  return Text(error!);
}

24. Empty State

A successful request may still return no data.

if (products.isEmpty) {
  return const Center(
    child: Text('No products available'),
  );
}

Therefore, a complete application should distinguish between:

  • Loading
  • Success with data
  • Success with no data
  • Error

25. Application State and MVVM

In an MVVM-style Flutter architecture, a ViewModel can hold presentation state and notify the UI when that state changes.

View
  ↓
ViewModel
  ↓
Repository
  ↓
Service
  ↓
API / Firebase / Database

Flutter's architecture guidance describes ViewModels as consumers of repository data, while repositories act as a source of application data.


26. ViewModel Example

class ProductViewModel extends ChangeNotifier {
  bool isLoading = false;
  List products = [];
  String? error;

  Future loadProducts() async {
    isLoading = true;
    error = null;
    notifyListeners();

    try {
      await Future.delayed(
        const Duration(seconds: 2),
      );

      products = [
        'Laptop',
        'Phone',
        'Tablet',
      ];
    } catch (e) {
      error = 'Failed to load products';
    } finally {
      isLoading = false;
      notifyListeners();
    }
  }
}

This demonstrates a ViewModel holding loading, data, and error state and notifying listeners when those values change.


27. Repository and Application State

A repository can act as the source of application data between the data sources and ViewModels.

API / Firebase
      ↓
Repository
      ↓
ViewModel
      ↓
UI

For example:

class UserRepository {
  Future getUser() async {
    // Fetch data from API or Firebase
    throw UnimplementedError();
  }
}

The ViewModel can then consume this repository instead of communicating directly with the API or Firebase service.


28. Application-Wide Session State

Some state needs to be shared across multiple features during an application session.

Examples include:

  • Current authenticated user
  • In-memory cache
  • Temporary application configuration
  • Current session information

Repositories can act as a source of application data and can also manage app-wide lifecycle state that needs to be shared across multiple ViewModels but does not need to persist beyond the current application session.


29. Application State vs Persistent Data

Application state and persistent data are related but are not exactly the same thing.

Application State Persistent Data
Represents current application conditions. Stored for later use.
May exist only during the current session. Designed to survive application restarts.
Can be held in memory. Can be stored in files, databases, or key-value storage.
Example: current loading status. Example: saved dark-mode preference.

State restoration and persistent storage solve different problems. Flutter provides restoration mechanisms for supported short-term UI state, while longer-term application data generally requires persistent storage. :contentReference[oaicite:9]{index=9}


30. State Restoration

State restoration is the process of restoring certain UI state after an application is recreated.

Examples of short-term state can include:

  • Selected tab
  • Scroll position
  • Unsubmitted form values
  • Navigation position

Flutter provides a restoration framework for supported widgets and application components. :contentReference[oaicite:10]{index=10}


31. Application State Flow

A typical application can follow this flow:

User Action
     ↓
Event Handler
     ↓
State Update
     ↓
State Notification
     ↓
Widget Rebuild
     ↓
Updated UI

For data loaded from an external source:

User Action
     ↓
ViewModel
     ↓
Repository
     ↓
API / Firebase
     ↓
New Data
     ↓
ViewModel State
     ↓
UI Rebuild

32. Practical Example: Login Application State

Consider a login application with three main states:

enum AuthStatus {
  loggedOut,
  loading,
  loggedIn,
}

The state can be used to control the UI:

Widget build(BuildContext context) {
  switch (authStatus) {
    case AuthStatus.loading:
      return const LoadingScreen();

    case AuthStatus.loggedIn:
      return const HomeScreen();

    case AuthStatus.loggedOut:
      return const LoginScreen();
  }
}

This approach makes different application states explicit and easier to reason about.


33. Practical Example: Shopping Cart

class CartState extends ChangeNotifier {
  final List _items = [];

  List get items => List.unmodifiable(_items);

  int get itemCount => _items.length;

  void addProduct(String product) {
    _items.add(product);
    notifyListeners();
  }

  void removeProduct(String product) {
    _items.remove(product);
    notifyListeners();
  }

  void clearCart() {
    _items.clear();
    notifyListeners();
  }
}

Multiple screens can observe this state:

Product Screen
      ↓
addProduct()
      ↓
Cart State
      ↓
notifyListeners()
      ↓
Cart Screen updates
      ↓
Checkout Screen updates

34. Practical Example: Theme State

class ThemeState extends ChangeNotifier {
  bool isDark = false;

  void toggleTheme() {
    isDark = !isDark;
    notifyListeners();
  }
}

The application theme can then depend on this state:

MaterialApp(
  themeMode: isDark
      ? ThemeMode.dark
      : ThemeMode.light,
)

35. Practical Example: Notification State

class NotificationState extends ChangeNotifier {
  int unreadCount = 0;

  void markAsRead() {
    if (unreadCount > 0) {
      unreadCount--;
      notifyListeners();
    }
  }

  void addNotification() {
    unreadCount++;
    notifyListeners();
  }
}

The notification badge can display the current state:

Badge(
  label: Text('$unreadCount'),
  child: const Icon(
    Icons.notifications,
  ),
)

36. State Management Options

Flutter provides several mechanisms for managing state. Built-in approaches include:

  • setState()
  • ValueNotifier
  • InheritedNotifier
  • InheritedWidget
  • InheritedModel

There are also many community packages for state management. Flutter's documentation notes that the appropriate choice depends on the application's complexity, team preferences, and the problem being solved. :contentReference[oaicite:11]{index=11}


37. When to Use Local State

Use local state when:

  • Only one widget needs the data.
  • The state is temporary.
  • The state does not need to be shared.
  • The state does not need complex business logic.

Example:

bool isPasswordVisible = false;

38. When to Use Application State

Application state becomes appropriate when:

  • Multiple screens need the same data.
  • Multiple widgets need to react to the same changes.
  • The state represents important application information.
  • The state needs a central source of truth.
  • The state is connected to business logic.
  • The state comes from APIs, databases, or Firebase.

There is no universal rule for classifying every variable. Flutter's documentation explicitly notes that state classification depends on the application and can change as the application grows. :contentReference[oaicite:12]{index=12}


39. Common Mistakes in Application State Management

  • Keeping duplicate copies of the same state.
  • Passing state through too many widget levels unnecessarily.
  • Putting all application state into one enormous class.
  • Mixing UI code with API or Firebase code.
  • Not handling loading and error states.
  • Not defining a clear source of truth.
  • Using complex state-management solutions for very small local state.
  • Forgetting to notify listeners after changing a ChangeNotifier.
  • Keeping sensitive information directly in UI widgets.
  • Not considering whether data needs to survive an application restart.

40. Best Practices

  • Keep state as close as practical to the widgets that use it.
  • Lift state up when multiple widgets need the same state.
  • Use a clear source of truth for shared application data.
  • Separate UI, state-management, repository, and service responsibilities.
  • Use setState() for simple local state.
  • Use an appropriate shared-state approach for larger application state.
  • Represent loading, success, empty, and error states explicitly.
  • Avoid unnecessary widget rebuilds.
  • Keep API and Firebase operations outside presentation widgets when the application architecture requires separation.
  • Use persistent storage when information must survive application restarts.
  • Choose a state-management approach based on application requirements rather than complexity for its own sake.

41. Practical Application Architecture

Flutter UI
    ↓
View / Screen
    ↓
ViewModel / State Manager
    ↓
Repository
    ↓
Service
    ↓
Firebase / REST API / Database

This type of layered architecture can help separate presentation logic from data access and application logic. Flutter's architecture guidance describes relationships between views, view models, repositories, and services.


42. Example Project Structure

lib/
├── main.dart
├── models/
│   ├── user.dart
│   └── product.dart
├── views/
│   ├── login_screen.dart
│   ├── home_screen.dart
│   ├── cart_screen.dart
│   └── profile_screen.dart
├── viewmodels/
│   ├── auth_viewmodel.dart
│   ├── product_viewmodel.dart
│   └── cart_viewmodel.dart
├── repositories/
│   ├── auth_repository.dart
│   └── product_repository.dart
└── services/
    ├── firebase_service.dart
    └── api_service.dart

43. Complete Application State Example

Consider a shopping application:

Application
│
├── Authentication State
│   ├── Logged Out
│   ├── Loading
│   └── Logged In
│
├── User State
│   ├── Name
│   ├── Email
│   └── Profile
│
├── Product State
│   ├── Loading
│   ├── Products
│   ├── Empty
│   └── Error
│
├── Cart State
│   ├── Items
│   ├── Quantity
│   └── Total
│
└── Theme State
    ├── Light
    └── Dark

44. Application State with Firebase Architecture

A Firebase-powered Flutter application can use the following architecture:

Flutter UI
    ↓
State Manager / ViewModel
    ↓
Repository
    ↓
Firebase Service
    ↓
Firebase Authentication
Cloud Firestore
Firebase Storage
Firebase Messaging

For example, a login operation could follow:

Login Button
    ↓
Auth ViewModel
    ↓
Auth Repository
    ↓
Firebase Authentication
    ↓
User Credential
    ↓
Authentication State
    ↓
Home Screen

45. Application State and Persistence

Some application state needs to remain available after the application is closed and reopened.

Examples:

  • Dark mode preference
  • Selected language
  • Onboarding completion
  • Saved user preferences
  • Offline application data

Such information requires a persistence mechanism rather than relying only on in-memory state. Flutter's architecture documentation includes key-value storage as one option for storing simple application data such as configuration and preferences.


46. In-Memory State vs Persistent State

In-Memory State Persistent State
Stored while the application is running. Stored for use after restart.
Fast to access. Requires storage read/write operations.
Can disappear when the application process ends. Designed to survive application restarts.
Example: loading status. Example: saved theme preference.

47. Important Difference: State vs Data

Not all data in an application has to be treated as application state.

For example:

Product catalog stored on server
        ↓
Repository retrieves data
        ↓
ViewModel exposes required state
        ↓
UI displays products

The server or database is the persistent source of the product data, while the application may maintain a current in-memory representation of that data as part of its UI state.


48. No Universal Rule

It is important to understand that there is no universal rule saying that a particular variable must always be application state or always be local state.

For example, a selected tab might initially be local to one screen. Later, the product requirements may require another part of the application to change the selected tab or restore it between sessions. In that situation, the same concept may become application state.

Flutter's documentation explicitly notes that the distinction between ephemeral and application state is conceptual rather than a strict technical rule. :contentReference[oaicite:13]{index=13}


49. Interview Questions

Q1. What is application state?

Application state is data representing the current condition of an application that may need to be shared across multiple parts of the application.

Q2. What are examples of application state?

Examples include authentication information, user preferences, shopping cart contents, notifications, and shared API data.

Q3. What is the difference between application state and ephemeral state?

Ephemeral state is generally local to a single widget, while application state is shared more broadly and may need to survive longer than the lifecycle of an individual widget.

Q4. What is lifting state up?

Lifting state up means keeping shared state above the widgets that need to use it so those widgets can work from the same source of truth.

Q5. What is a source of truth?

A source of truth is the authoritative place responsible for maintaining a particular piece of application data.

Q6. Why is application state important?

It allows different parts of an application to share and react to common data without maintaining disconnected copies of the same information.

Q7. What is ChangeNotifier?

ChangeNotifier is a Flutter SDK class that can notify listeners when its data changes.

Q8. What does notifyListeners() do?

It signals listening widgets that the state has changed so they can rebuild and display the updated state.

Q9. Does every variable need a state-management package?

No. Simple widget-specific state can often be managed with StatefulWidget and setState(). More complex or shared state may benefit from another state-management approach.

Q10. What is persistent state?

Persistent state is information stored so that it can be recovered after an application restart, such as user preferences.


50. Quick Revision

Application State
↓
Shared or important application data
Examples
↓
Login
Cart
User Profile
Theme
Notifications
API Data
Local State
↓
Usually belongs to one widget
Application State
↓
Usually shared across features
Lifting State Up
↓
Move shared state above widgets that use it
Source of Truth
↓
Authoritative location for important data
Persistent State
↓
Data saved for future sessions

51. Learning Outcome

After completing this topic, you should be able to explain what application state means, identify common types of application state, distinguish application state from ephemeral state, understand why shared state needs a clear source of truth, explain lifting state up, understand how ChangeNotifier and Provider can be used for shared state, and understand how application state can connect UI, ViewModels, repositories, Firebase, APIs, and persistent storage.


52. Useful Flutter Resources


53. JustAcademy Flutter Resources

For structured Flutter training and practical application development, explore the following resources:


54. Summary

Application state is the data that represents the current condition of an application and may need to be shared by multiple screens or features. Examples include login information, user preferences, shopping cart contents, notifications, and shared data loaded from APIs or Firebase.

Simple local state can often be handled with StatefulWidget and setState(), while shared application state can be managed using approaches such as lifting state up, ChangeNotifier, Provider, or other suitable state-management solutions. Flutter does not impose one universal state-management architecture; the appropriate choice depends on the application's requirements and complexity. :contentReference[oaicite:14]{index=14}

The most important concept to remember is:

Application State
      ↓
Single Source of Truth
      ↓
State Changes
      ↓
UI Rebuilds
      ↓
User Sees Updated Application
whatsapp